package com.hlsz.common.base;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.hlsz.common.util.SelectConditionUtil;
import lombok.Data;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

/**
 * @program: zhboot
 * @description: 基础查询条件
 * @author: Kenson
 * @create: 2021-05-26 15:06
 **/
@Data
@Slf4j
public class BaseConditionEntity {
    /**
     * aaa = "123"
     * aaa IN ("123","456")
     * aaa = "123"
     * aaa = "123"
     */
    private String field;
    /**
     * 可选的值
     * eq(等于)
     * ne(不等于)
     * like(包含)
     * leftlike(左包含)
     * rightlike(右包含)
     * notlike(不包含)
     * gt(大于)
     * ge(不小于)
     * lt(小于)
     * le(不大于)
     */
    private String connType;
    // value 值如果是一个区间，就用-隔开，如果是IN条件 就用 , 隔开 【符号都是半角】
    private String value;
    // and / or
    private String whereType;
    private List<String> exuldeUser;
    private List<String> lasSqls;
    private List<String> coList;
    // 内部维护一个配置对象
    @JsonIgnore
    private ConditionConfig conditionConfig = new ConditionConfig(this);

    /**
     * 条件构造器配置类, 可用于实现各类自定义配置
     * 这里使用内部类形式存在更好体现类关系
     * @Author Zdj
     * @Date 19:36 2024/4/23
     **/
    public static class ConditionConfig {

        /**
         * -- SETTER --
         *  设置Condition
         * @param baseConditionEntity 当前配置所适用的Condition对象
         */
        @Setter
        private BaseConditionEntity baseConditionEntity;

        // 可实现修改原有field值。默认使用defaultFieldHandler。默认实现 name -> "name" 示例: name = '小明' -> "name" = ‘小明’
        Function<String, String> defaultFieldHandler = field -> "\"" + field + "\"";

        public ConditionConfig() { }

        public ConditionConfig(BaseConditionEntity baseConditionEntity) {
            this.baseConditionEntity = baseConditionEntity;
        }

        /**
         * 获取字段处理器
         * @Author Zdj
         * @Date 19:53 2024/4/23
         * @return java.util.function.Function<java.lang.String, java.lang.String> 字段处理器
         **/
        public Function<String, String> getFieldHandler() {
            return defaultFieldHandler;
        }

        /**
         * 自定义字段处理器
         * @param customFunc 自己的实现, 入仓是源值
         * @return 自定义处理后的结果值
         */
        public ConditionConfig setFieldHandler(Function<String, String> customFunc) {
            defaultFieldHandler = customFunc;
            return this;
        }

        public BaseConditionEntity build() {
            return this.build(this.baseConditionEntity);
        }

        public BaseConditionEntity build(BaseConditionEntity bean) {
            if (bean == null) {
                return this.baseConditionEntity;
            }
            return bean;
        }
    }

    public BaseConditionEntity(){

    }

    public BaseConditionEntity(String field, String connType, String value) {
        this.field = field;
        this.connType = connType;
        this.value = value;
    }

    public BaseConditionEntity (String connType, List<String> lasSqls){
        this.connType = connType;
        this.lasSqls = lasSqls;
    }

    /**
     * 自定义配置 如: condition.config().build().toSqlPart()
     * @Author Zdj
     * @Date 20:05 2024/4/23
     * @return com.nice.common.sysbase.BaseConditionEntity.ConditionConfig
     **/
    public ConditionConfig config() {
        return this.conditionConfig;
    }

    /**
     * 设置外部配置对象
     * @Author Zdj
     * @Date 20:21 2024/4/23
     * @param config 外部配置对象
     * @return com.nice.common.sysbase.BaseConditionEntity
     **/
    public BaseConditionEntity conditionConfig(ConditionConfig config) {
        if (config != null) {
            this.conditionConfig = null;
            // 设置配置对象中引用为自己
            config.setBaseConditionEntity(this);
            this.conditionConfig = config;
        }
        return this;
    }

    /**
     * 转SQL片段, 前后不拼接AND 如: seq_num > '20'
     * @Author Zdj
     * @Date 10:43 2024/4/23
     * @return java.lang.String
     **/
    public String toSqlPart(){
        StringBuffer sb = new StringBuffer();
        switch (this.connType) {
            case "eq":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" = ")
                        .append("'").append(this.value).append("' ");
                break;
            case "ne":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" != ")
                        .append("'").append(this.value).append("' ");
                break;
            case "like":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" like ")
                        .append("'%").append(this.value).append("%' ");
                break;
            case "leftlike":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" like ")
                        .append("'%").append(this.value).append("' ");
                break;
            case "rightlike":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" like ")
                        .append("'").append(this.value).append("%' ");
                break;
            case "gt":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" > ")
                        .append("'").append(this.value).append("' ");
                break;
            case "ge":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" >= ")
                        .append("'").append(this.value).append("' ");
                break;
            case "lt":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" < ")
                        .append("'").append(this.value).append("' ");
                break;
            case "le":
                sb.append(this.conditionConfig.getFieldHandler().apply(this.field))
                        .append(" <= ")
                        .append("'").append(this.value).append("' ");
                break;
            case "and":
            case "or":
                sb.append(" ").append(this.connType).append(" ");
                break;
            default: {
                log.error("非法的connType, 请核查! -> {}", this.connType);
                throw new RuntimeException("非法的connType, 请核查!");
            }
        }
        // 拼接条件 and / or
        if (StrUtil.isNotBlank(whereType)) {
            return sb.append(" ").append(whereType).append(" ").toString();
        }
        return sb.toString();
    }

    //sql 片段
    public static BaseConditionEntity sqlPart(String k,Object v,String connType){
        BaseConditionEntity baseConditionEntity = new BaseConditionEntity();
        baseConditionEntity.setConnType("lastSql");
        String format = null;
        if(StrUtil.equals(connType,"eq")){
            format = StrUtil.format("AND  {} ='{}' ", k, v);
        }else if(StrUtil.equals(connType,"in")){
            format = StrUtil.format(" {} IN ({}) ", k, v);
        }else if(StrUtil.equals(connType,"notNull")){
            //format =" ";
            format = StrUtil.format(" {} is not Null ", k);
        }
        baseConditionEntity.setLasSqls(Arrays.asList(format));
        return baseConditionEntity;
    }

    /**
     * 默认配置的版本
     * @Author Zdj
     * @Date 20:26 2024/4/23
     * @param conditions 条件集合
     * @return java.lang.String 拼接好的SQL条件
     **/
    public static String toSqlForList(List<BaseConditionEntity> conditions) {
        return BaseConditionEntity.toSqlForList(conditions, null);
    }

    /**
     * 一个处理Condition集合将所有条件构建成SQL的工具方法，会去除最后无用的 and 或者 or
     * 如 conditions 有两个: "isControl" = 'Y' AND "disNo" = 'FF-ET-000002'
     * @Author Zdj
     * @Date 20:23 2024/4/23
     * @param conditions 条件集合
     * @param customConfig 自定义配置，应用到所有conditions
     * @return java.lang.String 拼接好的SQL条件
     **/
    public static String toSqlForList(List<BaseConditionEntity> conditions, ConditionConfig customConfig) {
        if (conditions == null || conditions.isEmpty()) {
            return "";
        }

        StringBuilder whereSql = new StringBuilder();
        for (int i = 0; i < conditions.size(); i++) {
            BaseConditionEntity current = conditions.get(i);
            BaseConditionEntity next = null;
            // 如果当前条件是 and 或者 or 则拼接 and / or
            if (Arrays.asList("and", "or").contains(current.getConnType().toLowerCase())) {
                whereSql.append(current.getConnType());
            }
            // 如果下一条数据不是 and 或者 or 则默认拼接 AND
            else if ((i + 1) <= conditions.size() - 1 && !Arrays.asList("and", "or").contains(conditions.get(i + 1).getConnType().toLowerCase())) {
                whereSql.append(
                        // 设置外部配置
                        current.conditionConfig(customConfig).toSqlPart()
                ).append(" AND ");
            }
            // 仅拼接条件
            else {
                whereSql.append(
                        // 设置外部配置
                        current.conditionConfig(customConfig).toSqlPart()
                );
            }
        }

        String substring = whereSql.toString();
        // 如果有后缀则去除
        if (Arrays.asList("and", "or").contains(conditions.get(conditions.size() - 1).getConnType())) {
            substring = StrUtil.removeSuffixIgnoreCase(whereSql.toString().trim(), conditions.get(conditions.size() - 1).getConnType()) + " ";
        }
        return substring;
    }

    /**
     * 一个处理Condition集合将所有条件构建成QueryWrapper的工具方法
     * @Author Zdj
     * @Date 16:04 2024/5/27
     * @param conditions 条件集合
     * @return com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
     **/
    public static QueryWrapper toQueryWrapperForList(List<BaseConditionEntity> conditions) {
        return SelectConditionUtil.parseWhereSql(conditions);
    }
}